查看原文
其他

DIY USB 电流表(9):Flash 模拟 EEPROM 存储累计电量

ohdarling 欧大的自留地 2024-07-04

在前一篇 《DIY USB 电流表(8):检测按键和绘制功率曲线》 中,整个 USB 电流表的固件开发已经进入尾声,目前我们已经完成了电压电流数据显示、功率计算、多页面切换、历史功率曲线绘制等功能.

为了更好地保持数据,在 USB 电流表重新上电的情况下,也可以恢复之前测量的数据,例如在测试充电宝容量时,中间会断开并重新连上负载,这个时候我们需要将之前记录的数据保存下来,继续累计负载消耗的电量。

但是在之前的原理图设计中,整个电路并没有添加 EEPROM,CH32V003 也没有自带 EEPROM,这时我们可以使用 CH32V003 的代码存储区域来模拟 EEPROM 保存数据,这次就来完成这个功能吧。

PS. 我也还是一个初学者,如果文章中有一些错误或不足,还请多多指教。


CH32V003 存储器结构

根据 CH32V003 的数据手册可以知道,CH32V003 拥有 16KB 的用户代码区域。

在 USB 电流表的固件编译之后,可以看到固件的大小,目前整个固件只占用约 12K  左右的空间,那可以就可以尝试使用剩余的空间来当作数据存储,模拟一下 EEPROM。

存储器特性

在使用 Flash 来模拟 EEPROM 时,需要通过数据手册关注一下 Flash 的一些特性,例如擦写时间和擦写寿命等。

存储器特性

从数据手册中可以看到,CH32V003 的 Flash 擦写 64 字节需要 2~3 毫秒的时间,如果在固件中太过频繁操作 Flash,会影响数据的统计和刷新,因此我们需要间隔一点的时间再来保存数据。

存储器寿命

同时,CH32V003 的内置存储器是有擦写寿命限制的,擦写次数超过限制可能会导致 Flash 的损坏,从而丢失数据,因此我们保存数据的频率也不能太高。

保存策略

一般来说,如果每分钟保存一次数据,在 20W 充电的情况,如果丢失一分钟数据,大约会丢失 20 * 1 / 60 = 0.33Wh 的统计数据,对于 10000 毫安时的充电宝来说,大概占比约为 0.33 / (10A * 3.7V) = 0.009,不到 1% 的比例,也算可以接受的。

另外如果按最低擦写次数 10K 来计算,每分钟保存一次数据,那么理论上持续运行 10K 分钟就会将擦写次数消耗完,大约是 166 小时。

当然我们也可以采取额外的保存策略来减缓数据写入,例如在总消耗电量没有变化时,就不写入 Flash,这样即使 USB 电流表一直插着电,也不会增加 Flash 擦写次数。

Flash 擦写方式

CH32V003 的 Flash 提供了多种擦写方式,从数据手册里面可以看到,它可以标准编程和快速编程。

对于我们的使用场景来说,因为只需要保存累计电量一个数据,理论上只需要 4 个字节即可应对大多数情况,因此这里使用快速编程擦写 64 字节的方式来进行 Flash 读写。


模拟存储

首先需要完成使用 Flash 模拟 EEPROM 的相关库方法,这里我们只使用一个页 64 字节来模拟存储。

定义头文件

对于累计电量这个简单数据来说,我们只需要 3 个方法来完成 EEPROM 相关的操作,包括加载、读取和写入。

flash_eeprom.h 中完成相关方法的定义。

定义地址

flash_eeprom.c 中,先定义一个 64 字节的内存缓存,用于存放模拟 EEPROM 中的数据,这样可以在读取和写入时都加速处理。

在这里,使用了 Flash 中用户代码的最后一页,即起始地址为 0x08003FC0 的 64 字节作为 EEPROM 存储区域。

实现读取和写入

读取 Flash

对于读取来说,实现起来非常简单,Flash 的地址已经映射到了内存地址 0x08003FC0 上,只需要直接将这一块内存区域复制到缓存中即可。

写入 Flash

写入 Flash 则稍微复杂一些,需要先执行擦除,再将 64 个字节写入 Flash 中。

在擦除和写入的前后,需要完成 Flash 的解锁和加锁操作。


读取和保存累计电量数据

有了模拟 EEPROM 相关的操作方法,就可以将 USB 电流表运行过程中的累计电量数据保存下来了,这样在断电后再次运行时,能继续延续上次统计的数据,实现更长周期的统计。

累计电量数据的读取和保存都将在 data_manager.hpp 中完成。

定义变量

这里定义了几个变量,用来确定数据保存的策略:

  • CAPACITY_SAVE_PERIOD 定义了 60000 毫秒保存一次,即每分钟保存一次

  • EEPROM_OFFSET_CAPACITY 定义了累计电量数据保存在模拟 EEPROM 中偏移为 0 的位置

  • capacity_last_saved_ms 用来保存上次保存累计电量的时间戳,用于判断是否到达时间间隔

  • capacity_last_save_val 用来保存上次保存累计电量的值,仅在数据有变化时才保存

加载数据

adc_setup 方法在系统启动时就会被调用,这个时候可以顺便将之前保存的累计电量数据加载出来。

保存数据

根据之前确定的数据保存策略,判断时间间隔和数据是否变化之后,调用 ch32v_eeprom_write 方法将数据保存到 Flash 中。

测试

这个时候,将固件编译完成,并烧录进入 DIY USB 电流表,在 USB 电流表后接上负载,并且等 Cap 字段有数据变化之后,将 USB 电流表从电源上断开,再重新连接上电源,就可以看到累计电量数据正确保存并重新加载了。


小结

至此,我们已经完成了 DIY USB 电流表固件的全部功能开发,对于 USB 电流表常见的使用场景,数据测量、历史曲线、数据保存等都已经很好地支持了。

这里再留一个小作业吧,上面的累计电量保存功能,只有读取和写入,没有清零,如果在测试完一个充电宝的容量之后,想要重新测试,就需要将之前保存的数据清零,那么在固件代码中该如何完成呢?

完成 DIY USB 的整体固件开发之后,为了让我们的 DIY USB 电流表更像一个正式产品,可以给它设计一个外壳,更美观的同时,还可以防止裸露的 PCB 接触到导体之后可能存在的短路风险。

那么,下一篇就来完成 DIY USB 电流表的外壳和面板设计吧。


USB 电流表开源地址

这个 USB 电流表所有资料已经开源,可以在以下仓库中获取,包含固件代码、PCB 生产 Gerber 文件、原理图和外壳 STL 文件。

https://github.com/ohdarling/CH32V003-USBMeter

硬件相关的源文件已经在立创开源平台开源,访问以下地址可以进行一键 PCB 下单和一键 BOM 配单操作:

https://oshwhub.com/wandaeda/ji-yu-ch32v003-de-usb-dian-liu-biao


DIY USB 电流表系列


其他 DIY 项目

30 元 DIY 一个柔性灯丝氛围灯

教程地址:https://xujiwei.com/blog/2024/04/diy-ambient-light/


参考资料

  • https://github.com/ohdarling/CH32V003-USBMeter

  • https://oshwhub.com/wandaeda/ji-yu-ch32v003-de-usb-dian-liu-biao

  • https://www.wch.cn/products/CH32V003.html


如果这个文章对你有帮助的话,可以关注、点赞、转发或分享,非常感谢 😃。

继续滑动看下一个
向上滑动看下一个

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存